import {Platform, PermissionsAndroid, Alert} from 'react-native'
import {
  check,
  request as requestPermission,
  openSettings,
  RESULTS,
  PERMISSIONS,
  Permission,
  AndroidPermission,
  IOSPermission,
} from 'react-native-permissions'
import CameraRoll from '@react-native-community/cameraroll'
import moment from 'moment'
import numeral from 'numeral'
import Locale from '@path/locale'
const RNFS = require('react-native-fs')
import Operation from './sub/operation'
import Colors from './sub/colors'

/**
 * 总工具类
 */
class Utils {
  static Operation = Operation
  static Colors = Colors

  //请求安卓外置内存卡权限
  static async requestExternalStoragePermission() {
    try {
      const granted = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE)
      return granted === RESULTS.GRANTED
    } catch (err) {
      console.error('Failed to request permission ', err)
      return false
    }
  }

  //保存base64图片
  static async saveBase64Img(base64Img: string, success: Function, fail: Function) {
    let permission = false
    if (Platform.OS === 'ios') {
      permission = true
    } else {
      permission = await this.requestExternalStoragePermission()
    }
    if (!permission) {
      return
    }
    const dirs = Platform.OS === 'ios' ? RNFS.LibraryDirectoryPath : RNFS.ExternalDirectoryPath // 外部文件，共享目录的绝对路径（仅限android）
    const filePath = `${dirs}/${'qr' + new Date().getTime()}.png`
    const imageDatas = base64Img.split('data:image/png;base64,')
    const imageData = imageDatas[1]

    RNFS.writeFile(filePath, imageData, 'base64').then(() => {
      try {
        CameraRoll.save(filePath)
          .then((e1) => {
            console.log('suc', e1)
            success && success()
          })
          .catch((e2) => {
            console.log('fail', e2)
          })
      } catch (e3) {
        console.log('catch', e3)
        fail && fail()
      }
    })
  }

  /**
   * 检查权限
   * @param name 权限名 如：PERMISSIONS.IOS.CAMERA
   * @returns
   */
  static async checkPermission(name: IOSPermission | AndroidPermission): Promise<boolean> {
    const permissionAlert = () => {
      const tips = {
        [PERMISSIONS.IOS.CAMERA]: {
          title: Locale.getString('permission.camera_title'),
          details: Locale.getString('permission.camera_desc'),
        },
        [PERMISSIONS.ANDROID.CAMERA]: {
          title: Locale.getString('permission.camera_title'),
          details: Locale.getString('permission.camera_desc'),
        },
        [PERMISSIONS.IOS.PHOTO_LIBRARY]: {
          title: Locale.getString('permission.photo_title'),
          details: Locale.getString('permission.photo_desc'),
        },
        [PERMISSIONS.ANDROID.READ_EXTERNAL_STORAGE]: {
          title: Locale.getString('permission.photo_title'),
          details: Locale.getString('permission.photo_desc'),
        },
        [PERMISSIONS.ANDROID.WRITE_EXTERNAL_STORAGE]: {
          title: Locale.getString('permission.photo_title'),
          details: Locale.getString('permission.photo_desc'),
        },
      }

      Alert.alert(tips[name]?.title || Locale.getString('common.alert'), tips[name]?.details || '', [
        {
          text: Locale.getString('action.cancel'),
          style: 'cancel',
        },
        {text: Locale.getString('action.confirm'), onPress: openSettings},
      ])
    }
    const perstatus = await check(name)
    return new Promise((resolve) => {
      if (perstatus === RESULTS.DENIED) {
        requestPermission(name)
          .then((res) => {
            if (res === RESULTS.GRANTED || res === RESULTS.LIMITED) {
              resolve(true)
            } else {
              permissionAlert()
              resolve(false)
            }
          })
          .catch(() => {
            resolve(false)
          })
      } else if (perstatus === RESULTS.GRANTED || perstatus === RESULTS.LIMITED) {
        resolve(true)
      } else {
        permissionAlert()
        resolve(false)
      }
    })
  }

  /**
   * 对字符串隐藏指定位数
   * @param {*} str 原字符串
   * @param {*} digit 隐藏位数，默认4位
   */
  static tranStringToSecure(str: string | number, digit: number = 4, holder: string = '*'): string {
    try {
      if (!str) {
        let result = ''
        for (let i = 0; i < digit; i++) {
          result += holder
        }
        return result
      }
      let strArr = String(str).split('')
      let realDigit = Math.min(digit, strArr.length) >= 0 ? Math.min(digit, strArr.length) : 4
      let startDigit = Math.floor((strArr.length - realDigit) / 2)

      let holders = []
      for (let i = 0; i < realDigit; i++) {
        holders.push(holder)
      }
      strArr.splice(startDigit, realDigit, holders.join(''))
      let result = strArr.join('')
      return result
    } catch (error) {
      console.log('tranStringToSecure error:', error)
      return '*'
    }
  }

  /**
   * 转换倒计时秒数成hh:mm:ss
   * @param countDownSec 秒数
   */
  static transCountDownToDate(countDownSec: number, isShowHour = true) {
    let originSec = Number(countDownSec)
    let day = Number(Math.floor(originSec / 60 / 60 / 24)) ?? '0'
    let hour = String(Math.floor(Number((originSec / 60 / 60) % 24)) + Number(day * 24)) ?? '00'
    let min = Math.floor((originSec / 60) % 60).toFixed(0) ?? '00'
    let sec = (originSec % 60).toFixed(0) ?? '00'

    if (!isShowHour) {
      min = `${Number(hour) * 60 + Number(min)}`
    }

    if (hour.length < 2) {
      hour = '0' + hour
    }
    if (min.length < 2) {
      min = '0' + min
    }
    if (sec.length < 2) {
      sec = '0' + sec
    }

    let str = ''
    if (!isShowHour) {
      str = `${min}:${sec}`
    } else {
      str = `${hour}:${min}:${sec}`
    }

    return str
  }

  static async saveImage(url: string, onSuccess: Function, onFail: Function) {
    const permission =
      Platform.OS === 'ios'
        ? await this.checkPermission(PERMISSIONS.IOS.PHOTO_LIBRARY_ADD_ONLY)
        : await this.requestExternalStoragePermission()

    if (permission) {
      if (Platform.OS === 'ios' || !url.includes('http') || url.includes('file://')) {
        //iOS或可以直接保存网络和本地图片，而安卓只能保存本地图片
        CameraRoll.save(url)
          .then((res) => {
            onSuccess(res)
          })
          .catch((err) => {
            onFail(err)
          })
      } else {
        //安卓，使用RNFS下载后保存
        const fileName = new Date().getTime() + '.png'
        const filePath = `${RNFS.DocumentDirectoryPath}/${fileName}`
        RNFS.downloadFile({fromUrl: url, toFile: filePath})
          .promise.then((res) => {
            if (res && res?.statusCode === 200) {
              CameraRoll.save('file://' + filePath)
                .then((result) => {
                  onSuccess(result)
                })
                .catch((error) => {
                  onFail(error)
                })
            } else {
              onFail()
            }
          })
          .catch((err) => {
            onFail(err)
          })
      }
    } else {
      onFail()
    }
  }

  /**
   * 下载文件
   * @param url 文件地址
   * @param fileName 文件名（默认时间戳.png）
   * @returns
   */
  static downloadFile(url: string, fileName: string = new Date().getTime() + '.png'): Promise<any> {
    const filePath = `${RNFS.DocumentDirectoryPath}/${fileName}`
    return new Promise((resolve, reject) => {
      RNFS.downloadFile({fromUrl: url, toFile: filePath})
        .promise.then((res: any) => {
          if (res && res?.statusCode === 200) {
            resolve(Platform.OS === 'ios' ? filePath : 'file://' + filePath)
          } else {
            reject()
          }
        })
        .catch((err: any) => {
          reject(err)
        })
    })
  }

  /**
   * 读取base64
   * @param filepath
   * @returns
   */
  static readFileAsBase64(filepath: string): Promise<any> {
    return RNFS.readFile(filepath, 'base64').then((res) => {
      return 'data:image/png;base64,' + res
    })
  }

  /**
   * 兼容显示时间
   * @param time 字符串或时间戳
   * @param format 格式
   * @param accuracy 精度
   */
  static adaptTime(time: any, format: string = 'YYYY-MM-DD HH:mm', accuracy: 'ms' | 's' = 's') {
    const mul = accuracy === 's' ? 1000 : 1
    return !isNaN(time * 1) ? moment(new Date(time * mul)).format(format) : time
  }

  static toDecimal2(x: number) {
    return numeral(x).format('0.00')
  }
}

export default Utils
